﻿using System.IO;

using NUnit.Framework;
using Ninject;

using System.Net.DnsToolkit.Bastard.PacketGenerator;
using System.Net.DnsToolkit.Configuration;
using System.Net.DnsToolkit.Packet;
using System.Net.DnsToolkit.Serializer;
using System.Net.DnsToolkit.Util;
using System.Net.DnsToolkit.TestUnit.Helper;

namespace System.Net.DnsToolkit.TestUnit.Bastard.PacketGenerator {
    [TestFixture]
    public class DomainPointerMatriochkasLoopTest {

        [Test]
        public void TestGetBytes() {

            var generator = new DomainPointerMatriochkasLoop();
            var bs = generator.GetBytes();
            var result = BitStringHelper.ByteArrayToString(bs);

            Assert.AreEqual("000000000001000000000000BFBCB9B6B3B0ADAAA7A4A19E9B9895928F8C898683807D7A7774716E6B6865625F5C595653504D4A4744413E3B3835322F2C292623201D1A1714110E0B0805023030C04CC04BC04AC049C048C047C046C045C044C043C042C041C040C03FC03EC03DC03CC03BC03AC039C038C037C036C035C034C033C032C031C030C02FC02EC02DC02CC02BC02AC029C028C027C026C025C024C023C022C021C020C01FC01EC01DC01CC01BC01AC019C018C017C016C015C014C013C012C011C010C00FC00EC00D00010001", result, "result");

        }

        [Test]
        public void TestReadMessage() {

            var generator = new DomainPointerMatriochkasLoop("012345678ABCDEF-F-E-D-C-B-A-9-8-7-6-5-4-3-2-1-", 15);
            var bs = generator.GetBytes();

            var message = DnsReader.Read(new MemoryStream(bs));
            // DarkDns toolkit is immune to Domain Pointer Matriochkas Loop attack
            Assert.IsNotNull(message, "message");
            Assert.AreEqual(1, message.Questions.Count, "count");
            Assert.AreEqual(64, bs.Length, "bs");
            Assert.AreEqual(375, message.Questions[0].QName.Name.Length, "name");


        }


        [Test]
        public void TestReadMessageCustom1() {

            var generator = new DomainPointerMatriochkasLoop("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 30);
            var bs = generator.GetBytes();

            var message = DnsReader.Read(new MemoryStream(bs));
            // DarkDns toolkit is immune to Domain Pointer Matriochkas Loop attack
            Assert.IsNotNull(message, "message");
            Assert.AreEqual(1, message.Questions.Count, "count");
            Assert.AreEqual(124, bs.Length, "bs");
            Assert.AreEqual(1940, message.Questions[0].QName.Name.Length, "name");


        }

        [Test]
        public void TestReadMessageCustomTooBig() {

            var generator = new DomainPointerMatriochkasLoop("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 50);
            var bs = generator.GetBytes();

            var message = DnsReader.Read(new MemoryStream(bs));
            // DarkDns toolkit is immune to Domain Pointer Matriochkas Loop attack
            Assert.IsNotNull(message, "message");
            Assert.AreEqual(1, message.Questions.Count, "count");
            Assert.AreEqual(512, bs.Length, "bs");
            Assert.AreEqual(0, message.Questions[0].QName.Name.Length, "name");


        }

        [Test]
        public void TestReadMessageCustombiggest() {

            var generator = new DomainPointerMatriochkasLoop("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 447);
            var bs = generator.GetBytes();

            var message = DnsReader.Read(new MemoryStream(bs));
            // DarkDns toolkit is immune to Domain Pointer Matriochkas Loop attack
            Assert.IsNotNull(message, "message");
            Assert.AreEqual(1, message.Questions.Count, "count");
            Assert.AreEqual(466, bs.Length, "bs");
            Assert.AreEqual(6664, message.Questions[0].QName.Name.Length, "name");


        }

        [Test]
        public void TestReadMessageCustomBest() {

            var generator = new DomainPointerMatriochkasLoop("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 191);
            var bs = generator.GetBytes();

            var message = DnsReader.Read(new MemoryStream(bs));
            // DarkDns toolkit is immune to Domain Pointer Matriochkas Loop attack
            Assert.IsNotNull(message, "message");
            Assert.AreEqual(1, message.Questions.Count, "count");
            Assert.AreEqual(210, bs.Length, "bs");
            Assert.AreEqual(6370, message.Questions[0].QName.Name.Length, "name");


        }

        public void TestReadMessageCustomMaxSize() {

            string s = "0";
            var qslengthlast = 0;
            for (int i = 0; i < 1000; i++) {
                for (int j = 1; j < 1000; j++) {

                    s = s + "0";
                    var generator = new DomainPointerMatriochkasLoop(s,j);
                    var bs = generator.GetBytes();

                    var message = DnsReader.Read(new MemoryStream(bs));
                    var bslength =bs.Length;
                    var qslength = message.Questions[0].QName.Name.Length;

                    if (bslength <= 512
                        && qslength > qslengthlast) {
                        qslengthlast = qslength;
                        Console.WriteLine("{0}: {1} : {2}", bs.Length, message.Questions[0].QName.Name.Length, qslength / bslength);
                        Console.WriteLine("{0} {1}", j, s);

                    }
                   
                }
            }

        }

    }
}
